package com.billdowney.util.file;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;

/**
 * 磁盘文件操作类
 * 
 * @author 超级小富翁 - BillDowney
 * @data 2017年4月14日 下午2:35:31
 */
public class FileUtil {

	public static final HashMap<String, String> mFileTypes = new HashMap<String, String>();

	static {
		mFileTypes.put("FFD8FFE0", "jpg");
		mFileTypes.put("89504E47", "png");
		mFileTypes.put("47494638", "gif");
		mFileTypes.put("49492A00", "tif");
		mFileTypes.put("424D", "bmp");
		mFileTypes.put("41433130", "dwg"); // CAD
		mFileTypes.put("38425053", "psd");
		mFileTypes.put("7B5C727466", "rtf"); // 日记本
		mFileTypes.put("3C3F786D6C", "xml");
		mFileTypes.put("68746D6C3E", "html");
		mFileTypes.put("44656C69766572792D646174653A", "eml"); // 邮件
		mFileTypes.put("D0CF11E0", "doc");
		mFileTypes.put("5374616E64617264204A", "mdb");
		mFileTypes.put("252150532D41646F6265", "ps");
		mFileTypes.put("255044462D312E", "pdf");
		mFileTypes.put("504B0304", "docx");
		mFileTypes.put("52617221", "rar");
		mFileTypes.put("57415645", "wav");
		mFileTypes.put("41564920", "avi");
		mFileTypes.put("2E524D46", "rm");
		mFileTypes.put("000001BA", "mpg");
		mFileTypes.put("000001B3", "mpg");
		mFileTypes.put("6D6F6F76", "mov");
		mFileTypes.put("3026B2758E66CF11", "asf");
		mFileTypes.put("4D546864", "mid");
		mFileTypes.put("1F8B08", "gz");
	}

	/**
	 * 读取文件路径下的所有文件
	 * 
	 * @params path 需要读取的路径
	 * @return JSONObject对象，包含已下值
	 * @params msg 提示信息
	 * @params sum 所有文件和文件夹总数
	 * @params fileList 文件列表
	 * @params folderList 提示信息
	 * @params fileSum 提示信息
	 * @params foldersum 提示信息
	 * @anthor billdonwey
	 */
	public static JSONObject readFolderList(String path) {
		JSONObject allList = new JSONObject();
		JSONArray fileList = new JSONArray();
		JSONArray folderList = new JSONArray();
		System.out.println("正在读取路径下的文件：" + path);
		if (path.equals("") || path == null) {
			allList.put("msg", "文件路径错误");
		} else {
			File filePath = new File(path);
			if (filePath.isDirectory()) {
				File[] tempList = filePath.listFiles();
				for (File file : tempList) {
					if (file.isFile()) {
						fileList.add(file);
					} else if (file.isDirectory()) {
						folderList.add(file);
					}
				}
				allList.put("sum", tempList.length);
				allList.put("msg", "读取成功");
			} else {
				allList.put("sum", 0);
				allList.put("msg", "路径指向一个文件，无法读取文件列表");
			}
		}
		allList.put("fileList", fileList);
		allList.put("folderList", folderList);
		allList.put("fileSum", fileList.size());
		allList.put("foldersum", folderList.size());
		return allList;
	}

	/**
	 * 打印readFolderList方法返回的JSONObject对象
	 * 
	 * @param files
	 * @anthor billdonwey
	 */
	public static void printFiles(JSONObject files) {
		System.out.println("提示信息：" + files.getStr("msg"));
		System.out.println("所有文件总数：" + files.getStr("sum"));
		System.out.println("文件夹总数：" + files.getStr("foldersum"));
		System.out.println("文件总数：" + files.getStr("fileSum"));
		for (int i = 0; i < files.getJSONArray("fileList").size(); i++) {
			System.out.println(files.getJSONArray("fileList").get(i));
		}
		for (int i = 0; i < files.getJSONArray("folderList").size(); i++) {
			System.out.println(files.getJSONArray("folderList").get(i));
		}
	}

	/**
	 * 删除给定的路径的文件或者文件夹包含的所有文件
	 * 
	 * @params filePath 文件或文件夹路径
	 * @return
	 * @anthor billdonwey
	 */
	public static boolean deleteAllFiles(String filePath) {
		System.out.println("正在删除：" + filePath);
		File file = new File(filePath);
		if (file.exists()) {// 判断文件是否存在
			if (file.isFile()) {// 判断是否是文件
				file.delete();// 删除文件
			} else if (file.isDirectory()) {// 否则如果它是一个目录
				File[] files = file.listFiles();// 声明目录下所有的文件 files[];
				for (int i = 0; i < files.length; i++) {// 遍历目录下所有的文件
					deleteAllFiles(files[i].getPath());// 把每个文件用这个方法进行迭代
				}
				file.delete();// 删除文件夹
			}
		} else {
			System.out.println("所删除的文件不存在：" + file.getPath());
			return false;
		}
		return true;
	}

	/**
	 * 创建目录
	 * 
	 * @params destDirName 目录路径
	 * @return 是否成功
	 * @anthor billdonwey
	 */
	public static boolean createDir(String destDirName) {
		File dir = new File(destDirName);
		if (dir.exists()) {// 判断目录是否存在
			return true;
		}
		if (!destDirName.endsWith(File.separator)) {// 结尾是否以"/"结束
			destDirName = destDirName + File.separator;
		}
		if (dir.mkdirs()) {// 创建目标目录
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 重命名文件或文件夹
	 * 
	 * @params originPath 原文件或文件夹路径
	 * @params newName 新文件名
	 * @anthor billdonwey
	 */
	public static boolean renameFile(String originPath, String newName) {
		String path = originPath.substring(0, originPath.lastIndexOf("/") + 1);
		File oldfile = new File(originPath);
		if (oldfile.isFile()) {
			if (!newName.contains(".")) {
				newName = newName + "." + getFileType(originPath);
			}
		}
		File newfile = new File(path + "/" + newName);
		if (!oldfile.exists()) {
			return false;// 重命名文件不存在
		}
		if (newfile.exists()) {// 若在该目录下已经有一个文件和新文件名相同，则不允许重命名
			System.out.println(newName + "，已经存在！");
			return false;
		} else {
			oldfile.renameTo(newfile);
		}
		return true;
	}

	/**
	 * 根据文件路径获取文件头信息
	 *
	 * @params filePath 文件路径
	 * @return 文件头信息
	 */
	public static String getFileType(String filePath) {
		if (mFileTypes.get(getFileHeader(filePath)) == null) {
			return filePath.substring(filePath.lastIndexOf(".") + 1);
		} else {
			return mFileTypes.get(getFileHeader(filePath));
		}
	}

	/**
	 * 根据文件路径获取文件头信息
	 *
	 * @params filePath 文件路径
	 * @return 文件头信息
	 */
	public static String getFileHeader(String filePath) {
		FileInputStream is = null;
		String value = null;
		try {
			is = new FileInputStream(filePath);
			byte[] b = new byte[4];
			/*
			 * int read() 从此输入流中读取一个数据字节。 int read(byte[] b) 从此输入流中将最多 b.length 个字节的数据读入一个
			 * byte 数组中。 int read(byte[] b, int off, int len) 从此输入流中将最多 len 个字节的数据读入一个 byte
			 * 数组中。
			 */
			is.read(b, 0, b.length);
			value = bytesToHexString(b);
		} catch (Exception e) {
			e.printStackTrace();
			return "";
		} finally {
			if (null != is) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return value;
	}

	/**
	 * 将要读取文件头信息的文件的byte数组转换成string类型表示
	 *
	 * @params src 要读取文件头信息的文件的byte数组
	 * @return 文件头信息
	 */
	private static String bytesToHexString(byte[] src) {
		StringBuilder builder = new StringBuilder();
		if (src == null || src.length <= 0) {
			return null;
		}
		String hv;
		for (int i = 0; i < src.length; i++) {
			// 以十六进制（基数 16）无符号整数形式返回一个整数参数的字符串表示形式，并转换为大写
			hv = Integer.toHexString(src[i] & 0xFF).toUpperCase();
			if (hv.length() < 2) {
				builder.append(0);
			}
			builder.append(hv);
		}
		return builder.toString();
	}

	/**
	 * 复制文件或整个文件夹内容
	 * 
	 * @params oldPath String 原文件路径 如：c:/test
	 * @params newPath String 复制后路径 如：c:/test/folder
	 * @return boolean
	 */
	public static boolean copyFolder(String oldPath, String newPath) {
		System.out.println(oldPath);
		System.out.println(newPath);
		try {
			(new File(newPath)).mkdirs(); // 如果文件夹不存在 则建立新文件夹
			File a = new File(oldPath);
			if (a.isDirectory()) {
				String[] file = a.list();
				File temp = null;
				for (int i = 0; i < file.length; i++) {
					if (oldPath.endsWith(File.separator)) {
						temp = new File(oldPath + file[i]);
					} else {
						temp = new File(oldPath + File.separator + file[i]);
					}
					if (temp.isFile()) {
						FileInputStream input = new FileInputStream(temp);
						FileOutputStream output = new FileOutputStream(newPath + "/" + (temp.getName()).toString());
						byte[] b = new byte[1024 * 5];
						int len;
						while ((len = input.read(b)) != -1) {
							output.write(b, 0, len);
						}
						output.flush();
						output.close();
						input.close();
					}
					if (temp.isDirectory()) {// 如果是子文件夹
						copyFolder(oldPath + "/" + file[i], newPath + "/" + file[i]);
					}
				}
			} else if (a.isFile()) {
				FileInputStream input = new FileInputStream(a);
				FileOutputStream output = new FileOutputStream(newPath + "/" + (a.getName()).toString());
				byte[] b = new byte[1024 * 5];
				int len;
				while ((len = input.read(b)) != -1) {
					output.write(b, 0, len);
				}
				output.flush();
				output.close();
				input.close();
			}
		} catch (Exception e) {
			System.out.println("复制内容操作出错");
			e.printStackTrace();
			return false;
		}
		return true;
	}

	/**
	 * 
	 * @Function: judgeFileOrFolderHave
	 * @Description: 该函数的功能描述
	 *
	 * @param path 文件或文件夹的路径
	 * @return 返回是否存在
	 *
	 * @author: 超级小富翁 - BillDowney
	 * @date: 2018年1月6日 下午4:15:13
	 */
	public static boolean judgeFileOrFolderHave(String path) {
		return new File(path).exists();
	}

	/**
	 * @Function: getFileSuffix
	 * @Description: 根据文件名获取文件后缀
	 * @param fileName 文件全名
	 * @return 获取到的后缀名，不存在的时候返回空字符串
	 * @author: 超级小富翁 - BillDowney
	 * @date: 2018年7月31日 下午5:13:25
	 */
	public static String getFileSuffix(String fileName) {
		if (fileName.contains(".")) {
			return fileName.substring(fileName.lastIndexOf(".") + 1);
		} else {
			return "";
		}
	}

	/**
	 * 读取文件内容
	 * 
	 * @param filePath
	 * @return
	 * @author: 唐路钧
	 * @date: 2019年1月25日 下午3:53:41
	 */
	public static String getFileContent(String filePath) {
		String content = "";
		try (FileReader reader = new FileReader(filePath); BufferedReader br = new BufferedReader(reader) // 建立一个对象，它把文件内容转成计算机能读懂的语言
		) {
			String line;
			// 网友推荐更加简洁的写法
			while ((line = br.readLine()) != null) {
				// 一次读入一行数据
				content += line;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return content;
	}
}
